package xlist

import (
	"strings"
	"sync"

	"gitee.com/xuesongtao/gotool/base"
)

// DNode 双向链表节点
type DNode struct {
	next, prev *DNode
	Data       interface{}
}

// NewDNode
func NewDNode(data interface{}) *DNode {
	return &DNode{
		Data: data,
	}
}

// String 打印
func (dn *DNode) String() string {
	return base.ToString(dn.Data, false)
}

// DList
type DList struct {
	safe   bool // 是否并发安全
	l      int  // 长度
	header *DNode
	tail   *DNode
	rwMu   *sync.RWMutex
}

// NewDList 初始化双向链表
// 默认非并发安全
func NewDList(safe ...bool) *DList {
	defaultSafe := false
	if len(safe) > 0 {
		defaultSafe = safe[0]
	}

	obj := &DList{safe: defaultSafe}
	if defaultSafe {
		obj.rwMu = new(sync.RWMutex)
	}
	return obj
}

// Append 追加
func (d *DList) Append(data interface{}) *DList {
	if d.safe {
		d.rwMu.Lock()
		defer d.rwMu.Unlock()
	}

	var addNode *DNode
	if node, ok := data.(*DNode); ok {
		addNode = node
	} else {
		addNode = NewDNode(data)
	}

	if d.header == nil {
		d.header = addNode
	} else {
		addNode.prev = d.tail
		d.tail.next = addNode
	}
	d.tail = addNode // 将新增节点添加到最后
	// fmt.Printf("n:%+v\n", d.tail)
	d.l++
	return d
}

// Len 长度
func (d *DList) Len() int {
	if d.safe {
		d.rwMu.RLock()
		defer d.rwMu.RUnlock()
	}
	return d.l
}

// IsEmpty 是否为空
func (d *DList) IsEmpty() bool {
	if d.safe {
		d.rwMu.RLock()
		defer d.rwMu.RUnlock()
	}
	return d.l == 0
}

// LPop 从头移除一个
// 返回为 nil 时, 链表为空
func (d *DList) LPop() *DNode {
	if d.safe {
		d.rwMu.Lock()
		defer d.rwMu.Unlock()
	}

	if d.l <= 0 {
		return nil
	}

	tmp := d.header
	if d.header == d.tail {
		d.header = nil
		d.tail = nil
		d.l--
		return tmp
	}
	d.header.next.prev = nil // 将第二个的前指针置空
	d.header = d.header.next
	d.l--
	return tmp
}

// Pop 从尾部删除一个
func (d *DList) Pop() *DNode {
	if d.safe {
		d.rwMu.Lock()
		defer d.rwMu.Unlock()
	}

	if d.l <= 0 {
		return nil
	}

	tmp := d.tail
	if d.tail == d.header { // 最开头的一个节点
		d.header = nil
		d.tail = nil
		d.l--
		return tmp
	}

	d.tail.prev.next = nil // 将倒数第二个指针置空
	d.tail = tmp.prev      // 重设尾部节点
	d.l--
	return tmp
}

// Front 第一个对象
func (d *DList) Front() *DNode {
	if d.safe {
		d.rwMu.RLock()
		defer d.rwMu.RUnlock()
	}
	return d.header
}

// Back 最后一个对象
func (d *DList) Back() *DNode {
	if d.safe {
		d.rwMu.RLock()
		defer d.rwMu.RUnlock()
	}
	return d.tail
}

// String 使用 Print 中的方法
func (d *DList) String() string {
	if d.safe {
		d.rwMu.RLock()
		defer d.rwMu.RUnlock()
	}

	if d.header == nil {
		return ""
	}
	buf := new(strings.Builder)
	node := d.header
	for node != nil {
		buf.WriteString("\nnode:" + node.String())
		node = node.next
	}
	return buf.String()
}
